package com.mdinic.blogovi.model;

import java.io.Serializable;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.PersistenceContext;
import javax.persistence.Table;
import javax.persistence.TypedQuery;
import javax.persistence.UniqueConstraint;
import javax.persistence.Version;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.tostring.RooToString;
import org.springframework.transaction.annotation.Transactional;

@Configurable
@Entity
@RooJavaBean
@RooToString
@RooJpaActiveRecord(finders = { "findFavsByPerson", "findFavsByPost" })
@Table(uniqueConstraints = @UniqueConstraint(columnNames = { "post", "person" }))
public class Fav implements Serializable {

    private static final long serialVersionUID = 1L;

    @NotNull
    @ManyToOne
    private BlogPost post;

    @NotNull
    @ManyToOne
    private Person person;

    @Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }

    public static TypedQuery<Fav> findFavsByPerson(Person person) {
        if (person == null)
            throw new IllegalArgumentException("The person argument is required");
        EntityManager em = Fav.entityManager();
        TypedQuery<Fav> q = em.createQuery("SELECT o FROM Fav AS o WHERE o.person = :person", Fav.class);
        q.setParameter("person", person);
        return q;
    }

    public static TypedQuery<Fav> findFavsByPost(BlogPost post) {
        if (post == null)
            throw new IllegalArgumentException("The post argument is required");
        EntityManager em = Fav.entityManager();
        TypedQuery<Fav> q = em.createQuery("SELECT o FROM Fav AS o WHERE o.post = :post", Fav.class);
        q.setParameter("post", post);
        return q;
    }

    public static TypedQuery<Fav> findFavsByPostAndPerson(BlogPost post, Person person) {
        if (post == null)
            throw new IllegalArgumentException("The post argument is required");
        EntityManager em = Fav.entityManager();
        TypedQuery<Fav> q = em.createQuery("SELECT o FROM Fav AS o WHERE o.post = :post AND o.person = :person",
                Fav.class);
        q.setParameter("post", post);
        q.setParameter("person", person);
        return q;
    }

    @PersistenceContext
    transient EntityManager entityManager;

    public static final EntityManager entityManager() {
        EntityManager em = new Fav().entityManager;
        if (em == null)
            throw new IllegalStateException(
                    "Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
        return em;
    }

    public static long countFavs() {
        return entityManager().createQuery("SELECT COUNT(o) FROM Fav o", Long.class).getSingleResult();
    }

    public static long countFavsByPerson(Person person) {
        TypedQuery<Long> createQuery = entityManager().createQuery(
                "SELECT COUNT(o) FROM Fav o WHERE o.person = :person", Long.class);
        createQuery.setParameter("person", person);
        return createQuery.getSingleResult();
    }

    public static List<Fav> findAllFavs() {
        return entityManager().createQuery("SELECT o FROM Fav o", Fav.class).getResultList();
    }

    public static Fav findFav(Long id) {
        if (id == null)
            return null;
        return entityManager().find(Fav.class, id);
    }

    public static List<Fav> findFavEntries(int firstResult, int maxResults) {
        return entityManager().createQuery("SELECT o FROM Fav o", Fav.class).setFirstResult(firstResult)
                .setMaxResults(maxResults).getResultList();
    }

    @Transactional
    public void persist() {
        if (this.entityManager == null)
            this.entityManager = entityManager();
        this.entityManager.persist(this);
    }

    @Transactional
    public void remove() {
        if (this.entityManager == null)
            this.entityManager = entityManager();
        if (this.entityManager.contains(this)) {
            this.entityManager.remove(this);
        } else {
            Fav attached = Fav.findFav(this.id);
            this.entityManager.remove(attached);
        }
    }

    @Transactional
    public void flush() {
        if (this.entityManager == null)
            this.entityManager = entityManager();
        this.entityManager.flush();
    }

    @Transactional
    public void clear() {
        if (this.entityManager == null)
            this.entityManager = entityManager();
        this.entityManager.clear();
    }

    @Transactional
    public Fav merge() {
        if (this.entityManager == null)
            this.entityManager = entityManager();
        Fav merged = this.entityManager.merge(this);
        this.entityManager.flush();
        return merged;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @Version
    @Column(name = "version")
    private Integer version;

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Integer getVersion() {
        return this.version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }

    public BlogPost getPost() {
        return this.post;
    }

    public void setPost(BlogPost post) {
        this.post = post;
    }

    public Person getPerson() {
        return this.person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }
}
